package sweet.helper

import java.io.{ File, FileReader, InputStream, FileInputStream, FileOutputStream }
import scala.collection.{ mutable, immutable, jcl }

// =====================================================
// === scala to java AND java collection enhancement ===
// =====================================================

/** Convert scala.Collection to java.util.Collection.
 * Note that java's iterator' remove method will not be implemented. */
class JCollection[A](col: scala.Collection[A]) extends java.util.AbstractCollection[A]{
  def iterator = new java.util.Iterator[A]{
    val elems = col.elements
    def hasNext = elems.hasNext
    def next = elems.next
    def remove = throw new UnsupportedOperationException("remove")
  }
  def size = col.size  
}
/** Campanion class */
object JCollection{
  def apply[A](col: scala.Collection[A]) = new JCollection(col)
}

/** Convert scala.Seq to java.util.List */
class JList[A](seq: scala.Seq[A]) extends java.util.AbstractList[A] {
  def get(idx: Int) = seq(idx)
  def size = seq.size
}
/** Campanion class */
object JList{
  //def apply[A](seq: scala.Seq[A]) = new JList(seq)
  def apply[A](tuples: (A)*) = new JList(tuples)
}

/** A shorter name for java.util.HashMap, but has a campanion object factory. */
class JMap[A,B] extends java.util.HashMap[A,B]
/*class JMap[A](map: scala.collection.Map[A, B]) extends java.util.AbstractMap[A, B] {
  def entrySet: java.utilSet = {
    new JCollection(map
  }
}*/
/** Campanion class the produce java map instance. */
object JMap{
  def apply[A, B](tuples: (A,B)*): JMap[A,B] = {
    val map = new JMap[A,B]
    for((k,v) <- tuples) map.put(k,v)
    map
  }
  //TODO: we should look more on java.util.AbstractMap to actually implement this like JList.
  def apply[A, B](imap: scala.collection.Map[A,B]): JMap[A,B] = {
    val map = new JMap[A,B]
    for((k,v) <- imap) map.put(k,v)
    map 
  }
}

/** Java java.util.Properties enhancement factory. */
object JProperties{ 
  def apply(name: String): java.util.Properties = apply(new FileInputStream(name))
  def apply(file: File): java.util.Properties = apply(new FileInputStream(file))
  def apply(ins: InputStream): java.util.Properties = {
    val props = new java.util.Properties
    props.load(ins)
    props
  }
  
  def apply(tuples: (String,String)*): java.util.Properties = {
    val props = new java.util.Properties
    for((k,v) <- tuples) props.setProperty(k,v)
    props
  }
  
  def loadFromXML(file: File): java.util.Properties = {
    val props = JProperties()
    props.loadFromXML(new FileInputStream(file))
    props
  } 
}

// =====================================================
// === java to scala AND java collection enhancement ===
// =====================================================

/** A scala Map that wraps java.util.Properties. */
class SProperties(props: java.util.Properties)
  extends jcl.Hashtable[String,String](props.asInstanceOf[java.util.Hashtable[String,String]]){
  def storeToXML(file: File, comment: String, enc: String){
    props.storeToXML(new FileOutputStream(file), comment, enc)  
  }
}
/** Campanion class */
object SProperties {
  def apply() : SProperties = new SProperties(JProperties())
  def apply(filename: String): SProperties = new SProperties(JProperties(filename))
  def apply(file: File): SProperties = new SProperties(JProperties(file))
  def apply(ins: InputStream): SProperties = new SProperties(JProperties(ins))
  
  def loadFromXML(file: File): SProperties = new SProperties(JProperties.loadFromXML(file))
}

/** A scala Map that wraps java.util.Map. */
class SMap[A,B](map: java.util.Map[A,B]) extends jcl.MapWrapper[A,B]{
  def underlying = map
}
/** Campanion class */
object SMap{
  def apply[A,B](map: java.util.Map[A,B]) = new SMap[A,B](map)
}

/** A shorter name for scala Map[String, String] type. */
class SStringMap(map: java.util.Map[String,String]) extends SMap[String, String](map)
/** A shorter name for Map[String, Int] type. */
class SIntMap(map: java.util.Map[String,Int]) extends SMap[String, Int](map)
/** A shorter name for Map[String, Object], or Map[String, AnyRef] type. */
class SObjectMap(map: java.util.Map[String,Object]) extends SMap[String, Object](map)
/** A shorter name for Map[String, Any] type. */
class SAnyMap(map: java.util.Map[String,Any]) extends SMap[String, Any](map)


//==============================================
//Common-Collections Goodies with Scala features
//==============================================
/** Factory to create org.apache.commons.collections.map.ListOrderedMap, and then
 * wraps it into scala's map. */
object OrderedMap{
  import org.apache.commons.collections.map.ListOrderedMap
  def apply[A,B](tuples: (A, B)*) = {
    val omap = new ListOrderedMap
    for((k,v) <- tuples) omap.put(k,v)
    new jcl.MapWrapper[A,B]{ def underlying = omap.asInstanceOf[java.util.Map[A,B]] }
  }
}
